namespace SimpleWebServices.Web.Mvc
{
    using System;
    using System.Diagnostics.CodeAnalysis;
    using System.Reflection;
    using System.Web.Mvc;
    using System.Web.Routing;

    [AttributeUsage(AttributeTargets.Method, Inherited = false, AllowMultiple = true)]
    public sealed class RoutingAttribute : Attribute
    {
        private string _methods;
        private string _path;

        public RoutingAttribute()
            : this("GET, HEAD", string.Empty)
        {
        }

        public RoutingAttribute(string methods, string path)
        {
            this.Methods = methods;
            this.Path = path;
        }

        public string Methods
        {
            get
            {
                return this._methods;
            }

            private set
            {
                if (null == value)
                {
                    throw new ArgumentNullException("value");
                }
                else if (0 == value.Length)
                {
                    throw new ArgumentOutOfRangeException("value");
                }

                this._methods = value;
            }
        }

        public string Path
        {
            get
            {
                return this._path;
            }

            private set
            {
                if (null == value)
                {
                    throw new ArgumentNullException("value");
                }
                else if (value.StartsWith("/", StringComparison.OrdinalIgnoreCase))
                {
                    throw new FormatException("Path should not start with /");
                }

                this._path = value;
            }
        }

        [SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters", Justification = "MethodInfo is used for type safety.")]
        public void Register(RouteCollection routes, Type type, MethodInfo action)
        {
            if (null == routes)
            {
                throw new ArgumentNullException("routes");
            }
            else if (null == type)
            {
                throw new ArgumentNullException("type");
            }
            else if (!type.IsSubclassOf(typeof(Controller)))
            {
                throw new ArgumentOutOfRangeException("type");
            }
            else if (null == action)
            {
                throw new ArgumentNullException("action");
            }

            string controller = type.Name.Replace("Controller", string.Empty);
            string[] methods = this.Methods.ToUpperInvariant().Replace(" ", string.Empty).Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
            foreach (string method in methods)
            {
                routes.MapRoute(
                    string.Concat(method, " ", this.Path),
                    this.Path,
                    new { controller = controller, action = action.Name },
                    new { method = new HttpMethodConstraint(method) });
            }
        }
    }
}